package com.dashan.frontend.client.widgets;

import static com.dashan.Constants.SALTED_PWDSHA;
import static com.dashan.Constants.USERNAME;

import com.dashan.frontend.client.DashanCookie;
import com.dashan.frontend.client.util.DashanRequestBuilder;
import com.dashan.frontend.client.util.DashanXmlReader;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.user.client.ui.Composite;
import com.gwtext.client.core.EventObject;
import com.gwtext.client.core.ExtElement;
import com.gwtext.client.core.Position;
import com.gwtext.client.data.FieldDef;
import com.gwtext.client.data.Record;
import com.gwtext.client.data.RecordDef;
import com.gwtext.client.data.StringFieldDef;
import com.gwtext.client.data.XmlReader;
import com.gwtext.client.widgets.Button;
import com.gwtext.client.widgets.Panel;
import com.gwtext.client.widgets.event.ButtonListenerAdapter;
import com.gwtext.client.widgets.form.FormPanel;
import com.gwtext.client.widgets.form.Label;
import com.gwtext.client.widgets.form.TextField;

public class LoginWidget extends Composite {
    public interface Listener {
        public void onLoginSuccess();
        public void onLoginCancel();
    }
    
    private final Panel root = new Panel();
    private final FormPanel loginFormPanel = new FormPanel();
    private final Panel logoutPanel = new Panel();
    
    private final Label welcomeMsg = new Label("Welcome");
    private final Label errorMsg = new Label();
    private final TextField userName = new TextField("User Name");
    private final TextField pwd = new TextField("Password");
    
    private final Button login = new Button("Login");
    private final Button logout = new Button("Logout");
    private ExtElement el;
    private Listener listener;
    
    public LoginWidget() {
        pwd.setPassword(true);
        pwd.setAllowBlank(false);
        userName.setAllowBlank(false);
        errorMsg.addClass("httpErrorMessage");
        errorMsg.setText("HttpError");
        errorMsg.hide();
        login.addListener(new ButtonListenerAdapter() {
            @Override
            public void onClick(Button button, EventObject e) {
                doLogin();
            }
        });
                
        loginFormPanel.setBorder(false);
        loginFormPanel.setLabelAlign(Position.RIGHT);
        
        loginFormPanel.add(errorMsg);
        loginFormPanel.add(userName);
        loginFormPanel.add(pwd);
        loginFormPanel.add(login);
    
        logout.addListener(new ButtonListenerAdapter() {
            @Override
            public void onClick(Button button, EventObject e) {
                DashanCookie.clear();
                checkLogin();
            } 
        });
        logoutPanel.add(welcomeMsg);
        logoutPanel.add(logout);
        
        root.add(loginFormPanel);
        root.add(logoutPanel);
        initWidget(root);
        checkLogin();
    }
    
    public void doLogin() {
        el = loginFormPanel.getEl();
        if (el != null) {
            el.mask("Loging in...");
        }
        
        DashanRequestBuilder builder = new DashanRequestBuilder("/getsalt");
        builder.addParameter(USERNAME, userName.getText());
        try {
            builder.sendRequest(new RequestCallback() {
                @Override
                public void onResponseReceived(Request request, Response response) {
                    if (Response.SC_OK == response.getStatusCode()) {
                        Record[] records = DashanXmlReader.fetchFromXml(response.getText(), 
                                new XmlReader("authentication", new RecordDef(new FieldDef[] {
                                        new StringFieldDef("salt")
                        })));
                        
                        String salt;
                        if (records.length == 1) {
                            salt = records[0].getAsString("salt");
                            getSessionId(salt);   
                        } else {
                            showErrorMessage("Server response error");
                        }
                    } else {
                        showErrorMessage(response.getStatusText());
                    }
                }
                @Override
                public void onError(Request request, Throwable exception) {
                    showErrorMessage(exception.getMessage());
                }
            });
        } catch (RequestException e) {
            showErrorMessage("Http connection Error.");
        }
    }
    
    public void setListener(Listener listener) {
        this.listener = listener;
    }
    
    private void getSessionId(String salt) {
        DashanRequestBuilder builder = new DashanRequestBuilder("/getsessionid");
        builder.addParameter(SALTED_PWDSHA, getSaltedPwdSha(salt));
        builder.addParameter(USERNAME, userName.getValueAsString());
        
        try {
            builder.sendRequest(new RequestCallback() {
                
                @Override
                public void onResponseReceived(Request request, Response response) {
                    if (Response.SC_OK == response.getStatusCode()) {
                        if (el != null) {
                            el.unmask();
                        }
                        Record[] records = DashanXmlReader.fetchFromXml(response.getText(), 
                                new XmlReader("authentication", new RecordDef(new FieldDef[] {
                                        new StringFieldDef("sessionid")
                        })));
                        
                        String sessionId;
                        if (records.length == 1) {
                            sessionId = records[0].getAsString("sessionid");
                            saveSessionId(sessionId);
                            errorMsg.hide();
                            checkLogin();
                            if (listener != null) {
                                listener.onLoginSuccess();
                            }
                        } else {
                            showErrorMessage("Server response error");
                        }
                    } else {
                        showErrorMessage(response.getStatusText());
                    }
                }
                
                @Override
                public void onError(Request request, Throwable exception) {
                    showErrorMessage(exception.getMessage());                    
                }
            });
        } catch (RequestException e) {
            showErrorMessage("Http connection Error.");
        }
    }
    
    private void saveSessionId(String sessionId) {
        DashanCookie cookie = new DashanCookie(userName.getValueAsString(), sessionId);
        cookie.save();
    }

    private void showErrorMessage(String message) {
        if (el != null) {
            el.unmask();
        }
        errorMsg.setText(message);
        errorMsg.show();
    }
    
    private String getSaltedPwdSha(String salt) {
        return pwd.getText() + salt;
    }
    
    private void checkLogin() {
        DashanCookie cookie = DashanCookie.load();
        if (cookie == null) {
            loginFormPanel.show();
            logoutPanel.hide();
        } else {
            loginFormPanel.hide();
            logoutPanel.show();
            welcomeMsg.setText("Hello! " + cookie.getUserName());
        }
    }
}
